package com.yonyou.crm.sys.quartz.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yonyou.crm.common.biz.service.BaseBizServiceImpl;
import com.yonyou.crm.common.exception.CrmBusinessException;
import com.yonyou.crm.common.model.util.IConverter;
import com.yonyou.crm.common.model.util.ModelUtil;
import com.yonyou.crm.common.page.entity.Page;
import com.yonyou.crm.sys.quartz.common.BeanExtendUtil;
import com.yonyou.crm.sys.quartz.dentity.DispatchGroupDO;
import com.yonyou.crm.sys.quartz.dentity.DispatchTaskDO;
import com.yonyou.crm.sys.quartz.ventity.DispatchTaskVO;
import com.yonyou.iuap.context.InvocationInfoProxy;
import com.yonyou.iuap.dispatch.CronTaskConfig;
import com.yonyou.iuap.dispatch.DispatchManager;
import com.yonyou.iuap.dispatch.ITask;

@Service("DispatchTaskBizService")
public class DispatchTaskBizService extends BaseBizServiceImpl<DispatchTaskDO> {
	private final Logger logger = LoggerFactory.getLogger(getClass());
	
	/**
	 * 保存任务 1、首先要在quartz中创建出任务来 2、创建本地的任务
	 * 
	 * @param vo
	 * @return
	 */
	public DispatchTaskVO saveDispatchTaskVO(DispatchTaskVO vo) {
		String s = UUID.randomUUID().toString();// 用来生成数据库的主键id非常不错。。
		vo.setId(s);
		String taskConfigSimp = this.getTaskConfigSimp(vo);
		if(vo.getGroupid() == null ){
			throw new CrmBusinessException("请选择任务分组!");
		}
		// 处理quartz集群的东西
		String success = this.addOrUpdateTask(taskConfigSimp);
		if("success".equals(success)){
			// 保存前端传过来的数据为VO，则需要将其转化为DO进行保存
			DispatchTaskDO uDO = ModelUtil.copyModel(vo, DispatchTaskDO.class);
			vo = ModelUtil.copyModel(saveVO(uDO), DispatchTaskVO.class);
			vo.setGroupName(getTaskGroupName(vo.getGroupid()));
		}
		return vo;
	}
	/**
	 * 验证cron表达式是否正确
	 * @param cronExpression
	 * @return
	 */
	public static boolean isValidExpression(final String cronExpression){
        CronTriggerImpl trigger = new CronTriggerImpl();
        try {
            trigger.setCronExpression(cronExpression);
            Date date = trigger.computeFirstFireTime(null);
            return date != null && date.after(new Date());
        } catch (Exception e) {
        	throw new CrmBusinessException("cron表达式有误!");
        }
    }
	/**
	 * 向集群中添加任务
	 * 
	 * @param data
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private String addOrUpdateTask(String data) {
		try {
			JSONObject dataJson = JSON.parseObject(data);
			boolean replace = dataJson.getBooleanValue("replace");

			Map recallData = new HashMap();
			JSONObject recallConfigJson = JSON.parseObject(dataJson
					.getString("recallConfig"));
			String recallConfigOption = recallConfigJson.getString("option");
			recallData.put("option", recallConfigOption);
			recallData.put("data", recallConfigJson.getString("data"));
			// String recallType = recallConfigJson.getString("recallType");

			JSONObject taskConfigJson = JSON.parseObject(dataJson
					.getString("taskConfig"));
			String triggerType = taskConfigJson.getString("triggerType");
			String url = JSON.parseObject(recallConfigOption).getString("url");
			String cronExpress = taskConfigJson.getString("cronExpress");
			isValidExpression(cronExpress);
			if ("CronTrigger".equals(triggerType)) {
				CronTaskConfig taskConfig = (CronTaskConfig) convertToCronTaskConfig(taskConfigJson);
				DispatchManager.add(taskConfig,
						(Class<? extends ITask>) Class.forName(url),
						recallData, replace);
				return "success";
			}
		} catch (Exception e) {
			logger.error("add task", e);
			throw new CrmBusinessException("添加任务失败!");
		}
		return "success";
	}

	/**
	 * 处理cron的定时器
	 * 
	 * @param dataJson
	 * @return
	 */
	private Object convertToCronTaskConfig(JSONObject dataJson) {
		CronTaskConfig taskConfig = new CronTaskConfig();
		taskConfig.setJobCode(dataJson.getString("jobCode"));
		taskConfig.setGroupCode(dataJson.getString("groupCode"));
		taskConfig.setCronExpress(dataJson.getString("cronExpress"));
		if (dataJson.get("endDate") != null) {
			taskConfig.setEndDate(dataJson.getDate("endDate"));
		}
		taskConfig.setPriority(dataJson.getIntValue("priority"));
		return taskConfig;
	}

	@Override
	protected void beforeSaveVO(DispatchTaskDO taskDO) {
		Date date = new Date();
		taskDO.setCreated_user_id("");
		taskDO.setTs(date);
		taskDO.setFirstime(date);
		taskDO.setEnableStatus(0);
		taskDO.setCreated_time(date);
		taskDO.setModified_time(date);
		taskDO.setTenantid(InvocationInfoProxy.getTenantid());
		byte nn = 0;
		taskDO.setIs_deleted(nn);
	}

	/**
	 * 更新任务
	 * 
	 * @param vo
	 * @return
	 */
	public DispatchTaskVO updateDispatchTaskVO(DispatchTaskVO vo) {
		if(vo.getGroupid() == null ){
			throw new CrmBusinessException("请选择任务分组!");
		}
		DispatchTaskVO oldVO = getVOById(vo.getId());
		// 1.删除集群中的任务
		String jobName = oldVO.getId();
		String groupName = oldVO.getGroupid();
		//代表没有改变分组，iuap没有封装，当修改任务分组时，如果获取当前的分组id的话，在iuap封装的方法中，将删除不掉原来的那个任务
//		if(!oldVO.getGroupid().equals(vo.getGroupid())){
			String taskMsg = DispatchManager.deleteJob(jobName, groupName);
			if (taskMsg != null) {
				logger.error(taskMsg);
				throw new CrmBusinessException("更新任务失败!");
				
			} 
//		}
		// 2.将任务重新添加到集群中
		String taskConfigSimp = this.getTaskConfigSimp(vo);
		this.addOrUpdateTask(taskConfigSimp);
		if (oldVO.getEnableStatus() == 1) {// 表示停用
			DispatchManager.pauseJob(vo.getId(), vo.getGroupid());
		}
//		vo.setCreated_time(oldVO.getCreated_time());
//		DispatchTaskDO taskDO = copyPropertiesTODO(vo);
//		Date date = new Date();
//		taskDO.setModified_time(date);
//		taskDO.setTs(date);
//		vo = copyPropertiesTOVO(super.updateVO(taskDO));
		DispatchTaskDO uDO = ModelUtil.copyModel(vo, DispatchTaskDO.class);
		vo = ModelUtil.copyModel(updateVO(uDO), DispatchTaskVO.class);
		vo.setGroupName(getTaskGroupName(vo.getGroupid()));
		return vo;
	}

	@Override
	protected void beforeUpdateVO(DispatchTaskDO taskDO) {
		super.beforeUpdateVO(taskDO);
		Date date = new Date();
		taskDO.setModified_time(date);
		taskDO.setTs(date);
	}

	/**
	 * 根据id删除任务 处理逻辑删除本地的任务数据时，同时删除任务调度集群内表的数据
	 * 
	 * @param id
	 * @return
	 */
	public int deleteDispatchTaskVO(String id) {
		String[] ids = new String[]{id};
		return dao.batchDelete(DispatchTaskDO.class, ids);
	}

	/**
	 * 删除
	 * 
	 * @param id
	 * @return
	 */
	public int deleteTask(String id) {
		DispatchTaskVO task = this.getVOById(id);
		if (task == null) {
			throw new CrmBusinessException("删除任务失败!");
		}
		String jobName = task.getId();
		String groupName = task.getGroupid();
		// 删除集群的任务
		String msg = DispatchManager.deleteJob(jobName, groupName);
		if (StringUtils.isNotEmpty(msg)) {
			logger.error(msg);
			throw new CrmBusinessException("删除任务失败!");

		} 
		// 删除本地的任务
		return deleteDispatchTaskVO(id);
	}

	/**
	 * 根据id查询V DO
	 * 
	 * @param id
	 * @return
	 */
	public DispatchTaskVO getVOById(String id) {
		DispatchTaskVO vo = copyPropertiesTOVO(getVOById(DispatchTaskDO.class,
				id));
		return vo;
	}

	/**
	 * 获取任务分页列表
	 * 
	 * @param page
	 * @param paramMap
	 * @return
	 */
	public Page<DispatchTaskVO> selectTask(Page<DispatchTaskVO> page,
			Map<String, Object> paramMap) {
		if(paramMap == null ){
			paramMap = new HashMap<String, Object>();
		}
		paramMap.put("tenantid", InvocationInfoProxy.getTenantid());
		Page<DispatchTaskDO> doPage = super.pageSelect(DispatchTaskDO.class, page, paramMap.keySet().toArray(new String[0]), paramMap.values().toArray(new Object[0]));
		Page<DispatchTaskVO> voPage = ModelUtil.copyPageModel(doPage, DispatchTaskVO.class, new IConverter<DispatchTaskDO,DispatchTaskVO>() {
			@Override
			public void convert(DispatchTaskDO origObj, DispatchTaskVO destObj) {
				// TODO 自动生成的方法存根
				destObj.setGroupName(getTaskGroupName(origObj.getGroupid()));
			}
		}); 
		return voPage;
	}
	
	private String getTaskGroupName(String groupId) {
		DispatchGroupDO groupDO = dao.getById(DispatchGroupDO.class, groupId);
		if (groupDO == null) {
			return "";
		}
		return groupDO.getName();
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Map<String, Object> triggerTask(String id) {
		Map retMap = new HashMap();
		DispatchTaskVO taskVO = getVOById(id);
		if (taskVO == null) {
			throw new CrmBusinessException("立即执行失败!");
		}
		if(taskVO.getEnableStatus() == 1){
			throw new CrmBusinessException("停用的任务不能立即执行!");
		}
		String jobName = taskVO.getId();
		String groupName = taskVO.getGroupid();

		String resumeTaskMsg = DispatchManager.triggerJob(jobName, groupName);
		if (resumeTaskMsg != null) {
			retMap.put("status", Integer.valueOf(0));
			retMap.put("msg", "立即执行失败!！");
			logger.error(resumeTaskMsg);
			throw new CrmBusinessException("立即执行失败!");

		} else {
			retMap.put("msg", "成功:任务操作成功！");
		}
		return retMap;
	}

	/**
	 * 更新停启用状态
	 * 
	 * @param id
	 * @param enableState
	 * @return
	 */
	public DispatchTaskVO updateEnableStatus(String id, Integer enableState) {
		// 查询出对应的VO来，将状态修改即可
		DispatchTaskVO taskVO = this.getVOById(id);
		// taskVO.setEnablestatus(enableState);
		String taskMsg = "";
		if (enableState == 0) {// 代表启用着，则使用暂停操作
			taskMsg = DispatchManager.pauseJob(taskVO.getId(),
					taskVO.getGroupid());
			taskVO.setEnableStatus(1);
		} else if (enableState == 1) {// 恢复
			taskMsg = DispatchManager.resumeJob(taskVO.getId(),
					taskVO.getGroupid());
			taskVO.setEnableStatus(0);
		}
		if (taskMsg != null) {
			logger.error(taskMsg);
			throw new CrmBusinessException("停启用失败!");
		}
		
		DispatchTaskDO taskDO = super.updateVO(ModelUtil.copyModel(taskVO, DispatchTaskDO.class,new IConverter<DispatchTaskVO, DispatchTaskDO>() {

			@Override
			public void convert(DispatchTaskVO origObj, DispatchTaskDO destObj) {
				// TODO 自动生成的方法存根
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				Date date  = new Date();
				try {
					if(origObj.getCreated_time() != null ){
						date = sdf.parse(origObj.getCreated_time());
						destObj.setCreated_time(date );
					}
				} catch (ParseException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
			}
		}));
		taskVO = ModelUtil.copyModel(taskDO, DispatchTaskVO.class,new IConverter<DispatchTaskDO, DispatchTaskVO>() {

			@Override
			public void convert(DispatchTaskDO origObj, DispatchTaskVO destObj) {
				// TODO 自动生成的方法存根
				destObj.setGroupName(getTaskGroupName(origObj.getGroupid()));
			}
		});
//		DispatchTaskVO vo = copyPropertiesTOVO(super
//				.updateVO(copyPropertiesTODO(taskVO)));
		return taskVO;
	}

	/**
	 * vo转换do
	 * 
	 * @param vo
	 * @return
	 */
	private DispatchTaskDO copyPropertiesTODO(DispatchTaskVO vo) {
		DispatchTaskDO taskDO = new DispatchTaskDO();
		BeanExtendUtil.copyProperties(taskDO, vo);
		return taskDO;
	}

	/**
	 * do转换vo
	 * 
	 * @param taskDO
	 * @return
	 */
	private DispatchTaskVO copyPropertiesTOVO(DispatchTaskDO taskDO) {
		DispatchTaskVO vo = new DispatchTaskVO();
		BeanExtendUtil.copyProperties(vo, taskDO);
		return vo;
	}

	/**
	 * iuap封装的格式，新增和修改时使用
	 * 
	 * @param taskVO
	 * @return
	 */
	private String getTaskConfigSimp(DispatchTaskVO taskVO) {
		String taskConfigSimp = "{\"replace\":true, \"recallConfig\":{\"data\":{\"tentantid\":\""+InvocationInfoProxy.getTenantid()+"\"},\"option\":{\"url\":\""
				+ taskVO.getUrl()
				+ "\"},\"recallType\":\"HTTP\"}, \"taskConfig\":{\"triggerType\":\"CronTrigger\",\"groupCode\":\""
				+ taskVO.getGroupid()
				+ "\",\"jobCode\":\""
				+ taskVO.getId()
				+ "\",\"priority\":0,\"cronExpress\":\""
				+ taskVO.getCronexpression()
				+ "\",\"endDate\":null,\"timeConfig\":{\"interval\":\""
				+ taskVO.getCronexpression()
				+ "\",\"intervalType\":\"HOUR\",\"isForever\":true}},\"note\":\"note\"}";
		return taskConfigSimp;
	}
}
